namespace BM.Tools.Xml.Schema
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Xml;
    using System.Xml.Schema;

    /// <summary>
    /// A helper class of the <see cref="XmlSchemaSet"/> class.
    /// </summary>
    public class SchemaSetHelper
    {
        private Dictionary<XmlQualifiedName, XmlSchemaAttributeGroup> attributeGroups;

        private Dictionary<XmlQualifiedName, XmlSchemaGroup> groups;

        private XmlSchema mainSchema;

        /// <summary>
        /// Initializes a new instance of the <see cref="SchemaSetHelper"/> class.
        /// </summary>
        /// <param name="schemaSet">
        /// The schema set.
        /// </param>
        public SchemaSetHelper(XmlSchemaSet schemaSet)
        {
            Set = schemaSet;
        }

        /// <summary>
        /// Gets the schema set.
        /// </summary>
        public XmlSchemaSet Set
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the dictionary of attribute groups with qualified names as keys.
        /// </summary>
        public IDictionary<XmlQualifiedName, XmlSchemaAttributeGroup> AttributeGroups
        {
            get
            {
                if (attributeGroups == null)
                {
                    attributeGroups = new Dictionary<XmlQualifiedName, XmlSchemaAttributeGroup>();                    
                    foreach (XmlSchema schema in Set.Schemas())
                    {
                        foreach (XmlQualifiedName name in schema.AttributeGroups.Names)
                        {
                            attributeGroups[name] = schema.AttributeGroups[name] as XmlSchemaAttributeGroup;
                        }
                    }
                }

                return attributeGroups;
            }
        }

        /// <summary>
        /// Gets the sictionary of groups with qualified names as keys.
        /// </summary>
        public IDictionary<XmlQualifiedName, XmlSchemaGroup> Groups
        {
            get
            {
                if (groups == null)
                {
                    groups = new Dictionary<XmlQualifiedName, XmlSchemaGroup>();
                    foreach (XmlSchema schema in Set.Schemas())
                    {
                        foreach (XmlQualifiedName name in schema.Groups.Names)
                        {
                            groups[name] = schema.Groups[name] as XmlSchemaGroup;
                        }
                    }
                }

                return groups;
            }
        }

        /// <summary>
        /// Gets the first schema in the schema set.
        /// </summary>
        public XmlSchema MainSchema
        {
            get
            {
                if (mainSchema == null)
                {
                    var schemas = Set.Schemas().Cast<XmlSchema>().ToArray();
                    if (schemas.Length > 0)
                    {
                        mainSchema = schemas[0];
                    }                    
                }

                return mainSchema;
            }
        }

        /// <summary>
        /// Gets the substitutions of the given schema element.
        /// </summary>
        /// <param name="schemaElement">
        /// The schema element.
        /// </param>
        /// <returns>
        /// the substitutions of the current schema element.
        /// </returns>
        public IEnumerable<XmlSchemaElement> GetSubstitutions(XmlSchemaElement schemaElement)
        {
            return Set.GlobalElements.Values.Cast<XmlSchemaElement>().Where(globalElement => globalElement.SubstitutionGroup.Equals(schemaElement.QualifiedName));
        }

        /// <summary>
        /// Creates a namespace manager for the main schema of the schema set.
        /// </summary>
        /// <returns>
        /// The namespace manager of the schema set main schema.
        /// </returns>
        public XmlNamespaceManager GetManager()
        {
            var namespaceManager = new XmlNamespaceManager(new NameTable());
            foreach (var qualifiedName in MainSchema.Namespaces.ToArray())
            {
                if (qualifiedName.Name != null)
                {
                    namespaceManager.AddNamespace(qualifiedName.Name, qualifiedName.Namespace);
                }
            }

            return namespaceManager;
        }
    }
}